﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace Week1.helper
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class DebugConsole
    {
        IDebugable[] oDebugObject = new IDebugable[10];

        particles.BaseParticle oConsole;
        Game oGame;
        SpriteFont oFont;
        SpriteFont oSmallFont;

        SpriteBatch oBatch;
        Texture2D oFrame;

        RenderTarget2D oRenderTarget;
        
        Vector2 oTextPos;
        DebugMsg oMsg;
        
        public bool ShowMessage = false;
        private static DebugConsole instance;

        private DebugConsole()
            : base()
        {

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        /// <param name="position"></param>
        public void setPosition(int index, Vector3 position)
        {
            oConsole.oPosition[index] = position;
        }

        /// <summary>
        /// 
        /// </summary>
        public static DebugConsole Instance
        {

            get 
            {
                if (instance == null)
                {
                    instance = new DebugConsole();
                }
                return instance;
            }
        }

        protected int iRegisterCount = 0;
        protected int iCurrentDebug = 0;

        public void registerDebug(IDebugable debug)
        {
            oDebugObject[iRegisterCount] = debug;
            iRegisterCount++;
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public void Initialize(Game game, player.Camera camera)
        {
            oGame = game;
            
            oTextPos = new Vector2(10, 5);
            oFont = oGame.Content.Load<SpriteFont>("defaultfont");
            oSmallFont = oGame.Content.Load<SpriteFont>("smallfont");
            oBatch = new SpriteBatch(oGame.GraphicsDevice);
            oRenderTarget = new RenderTarget2D(oGame.GraphicsDevice, 1024, 512, false, SurfaceFormat.Rg32, DepthFormat.None);
            oFrame = oGame.Content.Load<Texture2D>("debugscreen");
            
            oConsole = new particles.BaseParticle(oGame, null, camera, 1, 1);
            oConsole.bUseBillboard = false;
            oConsole.bUseDepth = false;
            oConsole.bUseCameraSettings = false;

            oConsole.Initialize();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="gametime"></param>
        public void update(GameTime gametime)
        {

            handleKeyboard();


            if (ShowMessage)
            {
                oMsg = oDebugObject[iCurrentDebug].getDebugMsg(bShowNextInstance);

                oMsg.message = "Debug class # " + (iCurrentDebug+1) + " of " + iRegisterCount+ 
                    "\n" + oDebugObject[iCurrentDebug].ToString() + 
                    "\n" + oMsg.message;

                if (bShowNextInstance)
                    bShowNextInstance = false;

                oConsole.oPosition[0].X = oMsg.position.X;
                oConsole.oPosition[0].Y = oMsg.position.Y;
                oConsole.oPosition[0].Z = oMsg.position.Z;

                if (oConsole.bUseCameraSettings)
                    oConsole.iScale = oMsg.scale;
                else
                    oConsole.iScale = 1;

                oConsole.Update(gametime);
            }
        }

        // keyboard flags
        protected bool bD = false;
        protected bool bC = false;
        protected bool bF3 = false;
        protected bool bShowNextInstance = false;
        protected bool bF4 = false;

        /// <summary>
        /// 
        /// </summary>
        private void handleKeyboard()
        {
            KeyboardState state = Keyboard.GetState();

            if (state.IsKeyDown(Keys.F1) && !bD)
            {
                ShowMessage = !ShowMessage;

                bD = true;
            }

            if (state.IsKeyDown(Keys.F2) && !bC)
            {
                oConsole.bUseBillboard = ! oConsole.bUseBillboard;
                oConsole.bUseCameraSettings = ! oConsole.bUseCameraSettings;
            }

            if (state.IsKeyDown(Keys.F3) && !bF3)
            {
                iCurrentDebug++;
                if (iCurrentDebug >= iRegisterCount)
                {
                    iCurrentDebug = 0;
                }

                bF3 = true;
            }

            if (state.IsKeyDown(Keys.F4) && !bF4)
            {
                bShowNextInstance = true;
                bF4 = true;
            }

            bD = !state.IsKeyUp(Keys.F1);
            bC = !state.IsKeyUp(Keys.F2);
            bF3 = !state.IsKeyUp(Keys.F3);
            bF4 = !state.IsKeyUp(Keys.F4);

        }
        /// <summary>
        /// Call this method from draw method of game class. This method must be called before any other call to draw is made.
        /// It creates in memomry render target.
        /// </summary>
        /// <param name="gameTime"></param>
        public void PreDraw(GameTime gameTime)
        {
            if (ShowMessage)
            {
                SpriteFont oUsefont;
                if (oConsole.bUseCameraSettings)
                    oUsefont = oFont;
                else
                    oUsefont = oSmallFont;

                oGame.GraphicsDevice.SetRenderTarget(oRenderTarget);

                oGame.GraphicsDevice.Clear(Color.FromNonPremultiplied(0, 255, 0, 30));

                oBatch.Begin();

                if (oConsole.bUseCameraSettings)
                    oBatch.Draw(oFrame, new Rectangle(0,0,1024,512), Color.White);
                
                oBatch.DrawString(oUsefont, oMsg.message, oTextPos, Color.White);
                oBatch.End();

                oGame.GraphicsDevice.SetRenderTarget(null);

                oConsole.oTexture = (Texture2D)oRenderTarget;
                    
                oGame.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.FromNonPremultiplied(0, 0, 0, 0), 1, 0);
            }
        }

        public void draw(GameTime gameTime)
        {
            if (ShowMessage)
                oConsole.Draw(gameTime);
        }


    }
}
